Go训练营第六课问题收集
2021年11月4日 更新
开启更多功能,提升办公效能
  1. Go channel,感觉有点儿像 C 里的 goto,会打破代码原本的那种从上至下的阅读性,让代码变得更加难以阅读,老师怎么看待这件事儿?有什么并发编程规范可以约束么?
  1. 什么是 sentinel error?
  1. 如何无🔐锁编程?有什么套路可以学
  1. 一写一读,或者一写多读, 一定要加锁吗? 一定需要原子操作吗?有没有不加锁, 不使用 atomic 函数就可以 safe 的方法? 例如一个数据库结构体的指针,在数据库更换实例的时候,服务代码里会创建一个新的数据库连接池对象的结构体的指针,覆盖原来的数据库指针的时候,是不是一定要加锁,或者一定要使用 atomic 包进行原子 Store Load?
  1. 我们可以认为 RWLock 和 Atomic(COW) 是适合读多写少的场景,对吗? 请问能举例读多写多或是读少写多的场景和适合的解法吗?
  1. errgroup. 一个业务,需要调用多个服务,我最开始也是开多个 goroutine 单独去调用的。但是,我老大说开 goroutine 会有代价的,就不让我用了,只能改成串行。我感觉是一种空间换时间的思想。老师说说你的看法呗,谢谢。
  • 答:测试数据说话就好,具体要看业务场景的
  1. GOMAXPROCS 里有 panic。
  • 答:因为非法 fatal 错误,要 panic 的,这种错误一般要退出程序排查的
  1. context 使用时是不是大量的存在以下代码,本来函数调用的都要起个 goroutine?
func (s *server) DoSomething(ctx context, in... args){
result = make(struct{})
// 这如果 panic 咋整?
go doSomethingEssential(result)

select {
case rsp <- result:
xxx
case x <- ctx.Done():
xxx
}
}
  • 答:G 里面 panic 可以参考下毛老师上节课讲的处理方法,只要吧 error 接受传递出去处理即可
  1. 如果一个 struct,有很多方法,这些方法都是内部 go 出去的,那 context 是否可以挂到 struct 内部,因为这个 context 只控制内部的 goroutine。这种情况如果每个方法都传递 context 是不是就比较重?
  • context 并没有那么美好。Go 官方建议我们把 Context 作为函数的第一个参数,甚至连名字都准备好了。这造成一个后果:因为我们想控制所有的协程的取消动作,所以需要在几乎所有的函数里加上一个 Context 参数。很快,我们的代码里,context 将像病毒一样扩散的到处都是
  1. 那么如果子 context 的 key 跟父 context 的 key 一样的话, 因为 contxt 不能修改,这个时候是要 cancel context 吗? 或者用新的 withValue 但是读取的时候不是递归么, 那么上面的那个 Key 怎么获取?
  1. context 中插入 Map 的时候。除了用 M2 覆盖 M1, 如果不考虑 上游 不看到 下游的情况,需要共享的话,是否可以使用 sync.Map?
  1. goroutine 间的数据共享实际疑问:(1)程序中经常有一个主 goroutine 勤勤恳恳做事情,并更新自己的状态; 而可能有个 goroutine 用于外部请求服务如 gRPC,request 过来的, 查询获取服务的状态;这些状态除了各种 Mutex 还有啥优雅方式?(2) gRPC 服务这边调用的方法,用 package 级别的 Public 方法好,还是 service 对象的 Public 方法?如果是 service 对象,怎么合适给 GRPC 服务,创建 GRPC 服务是注入吗?经常看到有用包级别的 Public 方法,实际是获取一个单例 service 对象的 Public 方法;对于以上情况老师有什么好的建议

通过 kratos 代码的阅读,这些疑问已基本释怀


  1. 怎样看 Dave 说的 "context isn't for cancellation"? https://dave.cheney.net/2017/08/20/context-isnt-for-cancellation
  • dav 的建议是 context 只传请求上下文相关的数据,而 cancel 是请求生命周期相关的操作,应该保持 API 设计的正交。另外 cancel 的信号并不完整,因为发起 cancel 的人,不知道是否完成 cancel 了。


  1. 如果每个调用方法都传 context 做超时控制,那是不是每个方法都需要 select case <-ctx.done.?感觉有些麻烦。有更好的方式吗?


  1. sync.Cond 大概在什么场合使用?需要相互通知机制?实际项目这个用的多吗?
  1. 请问在不知道有什么 key 的情况下,怎么 copy context?
  1. copy context 是指什么?如果是指怎么从上一个 context 生成新的 context 的话,可以使用 context.withXXX 那几个方法,第一个参数传入上一个 context
  1. context 应该不需要 copy
  1. chan 的底层也是由 mutex 实现的话, 这种方式和通过共享内存的方式有什么优势?读写数据的时候不是也需要争抢锁吗?
  1. 共享内存和消息传递,这两个是属于编程模型上的区别,chan 底层使用 mutex 实现,这个是实现的手段,chan 的这种模式,简化编程模型
  1. 什么是单飞模式?什么是双飞模式?
  1. 参考 golang.org/x/sync/singleflight?
  1. 适合秒杀场景,或者热点归并回源,可以用来防止 cache 穿透导致的雪崩
  1. trace 怎么结合 context 做才 graceful
  1. 参考 opentracing-go,毛老师后面讲 tracing 的时候,会重点讲
  1. 毛老师课件中讲到放到 pool 中的对象,说不定什么时候就被回收了,我看 zap 源码的时候,它的 pool 是固定 1024 字节,这种也会被回收吗?什么情况下会被回收
  1. pool 不会回收,回收的是 pool 里缓存的对象
  1. 课程中提到了很多 go 的并发模型,每种并发模型都有具体的适用场景么?
  1. 数据库实例如何共享,现在使用全局变量(初始化配置之后,将全局变量赋值),是否不够优雅以及有什么隐患
  1. 足够优雅
  1. grpc client 请求 grpc server,如果 grpc server 中开启一个 goroutine 并且没有通过 sync.WaitGroup.Wait(),client 请求完毕之后会 cancel context,假设 goroutine 中使用到了 context,那么会 deadline,除了新建一个 context,还有没有其他比较好的方式
  1. 发现在go使用通道的时候会造成fatal error: all goroutines are asleep - deadlock!这种panic,然而在编译的时候没有报错。如果我们面对一个复杂大型项目,该如何写好自身代码防止这种情况发生。(有时候如果测试涉及分支或数据也没有涵盖全面。)
  1. 能不能搞一个完整的项目包括今天这些知识的实践
  1. 想听听老师在没有导师的情况下是如何建立自己的技术体系的,现在的技术多而杂很容易在选择中迷失,谢谢!